import dataclasses
import uuid

from webutils.tornado.responses import Response
from message_broker import services
from message_broker.const import ActType, UserGroup, UserRole
from message_broker.websocket import (mixin_chat, mixin_state,
                                      mixin_handwriting, mixin_counter,
                                      BrokerHandler, User)


@dataclasses.dataclass
class UserLoginMessage:
    uid: str
    nm: str
    pv: int
    act: str = str(ActType.USER_ONLINE.value)


class DemoWebSocket(mixin_chat.ChatMixin, mixin_state.StateMixin,
                    mixin_handwriting.HandwritingMixin,
                    mixin_counter.CounterMixin, BrokerHandler):
    def check_origin(self, origin):
        return True

    async def authorize(self, conn, room_id=None):
        # token 是一个占位参数，将来会用于作校验
        token = self.get_argument('token', None)
        if not token:
            await self.write_response(
                Response(errcode='500', errmsg='token is expected'))
            self.abort('[authorize] token not provided')

        self.session.room_id = room_id
        self.session.id = uuid.uuid4().hex

    async def on_act_register(self, args, conn):
        self.session.is_registered = True
        user_id = args.get('uid')
        if not user_id:
            await self.write_response(
                Response(errcode='500', errmsg='uid is expected'))
            self.abort('[register] uid not provided')
        name = args.get('nm', '')
        self.session.user = User(id=user_id, name=name, role=UserRole.STUDENT)
        user_info = args
        # 登录的时候，存储所有的用户信息
        # 有个接口需要根据存储的用户信息进行筛选
        user_service = services.UserService(conn, room_id=self.session.room_id)
        await user_service.login_user(user_id, UserGroup.ALL, user_info)

        # 统计观看量
        # 这个值类似 pv，其实可以通过 nginx 进行汇总
        counter = services.Counter(
            conn,
            room_id=self.session.room_id,
            counter_id='pv',
        )
        # 避免客户端出现bug， dos 中控server
        # 数据都存储在 redis 中，所以需要考虑内存占用问题
        if await counter.count() <= 10000:
            total_pv = await counter.add(user_id)

        login_message = UserLoginMessage(
            uid=user_id,
            nm=name,
            pv=total_pv,
        )
        await self.broadcaster_app.send_task(
            'broadcast_login',
            dataclasses.asdict(login_message),
            group=UserGroup.ALL,
        )

        resp = Response(
            type='21',
            act=str(ActType.MESSAGE_ACK.value),
            stat='1',
        )
        await self.write_response(resp)
